package utilities;

import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;

public class JSONArchive implements Archive {
	// Instance Variables
	public Map<String, String> attributes;
	public Map<String, List<String>> attributeLists;
	public Map<String, Archive> oneRelationships;
	public Map<String, List<Archive>> manyRelationships;
	
	
	// Constants
	public static final String ATTRIBUTES_KEY = "attributes";
	public static final String ATTRIBUTE_LISTS_KEY = "attributeLists";
	public static final String ONE_KEY = "one";
	public static final String MANY_KEY = "many";
	
	
	// Constructors
	/**
	 * Constructor: initializes empty HashMaps
	 */
	public JSONArchive() {
		this.attributes = new HashMap<String, String>();
		this.attributeLists = new HashMap<String, List<String>>();
		this.oneRelationships = new HashMap<String, Archive>();
		this.manyRelationships = new HashMap<String, List<Archive>>();
	}
	
	
	// Put methods
	public void putClassName(String key, String className) {
		if (key != null && className != null) {
			this.attributes.put(key + "CLASSNAME", className);
		}
	}
	
	public void putAttribute(String key, String value) {
		if (key != null && value != null) {
			this.attributes.put(key, value);
		}
	}
	
	public void putAttributeList(String key, List<String> value) {
		if (key != null && value != null) {
			this.attributeLists.put(key, value);
		}
	}
	
	public void putOneRelationship(String key, Archiveable value) {
		if (key != null && value != null) {
			this.oneRelationships.put(key, value.save());
		}
	}
	
	public void putManyRelationship(String key, List<? extends Archiveable> value) {
		if (key != null && value != null) {
			List<Archive> list = new ArrayList<Archive>(value.size());
			for (Archiveable item : value) {
				list.add(item.save());
			}
			this.manyRelationships.put(key, list);
		}
	}
	
	public void putPrimitiveToPrimitiveMap(String key, Map<String, String> map) {
		if (key != null && map != null) {
			// Get the keys and create an empty list for values
			List<String> keyList = new ArrayList<String>(map.keySet());
			List<String> valueList = new ArrayList<String>(keyList.size());
			
			// Iterate through each key, adding its value to the valueList
			for (String aKey : keyList) {
				String aValue = map.get(aKey);
				valueList.add(aValue);
			}
			
			// Save both lists separately
			this.putAttributeList(key + "KEY", keyList);
			this.putAttributeList(key + "VALUE", valueList);
		}
	}
	
	public void putPrimitiveToArchiveableMap(String key, Map<String, ? extends Archiveable> map) {
		if (key != null && map != null) {
			// Get the keys and create an empty list for values
			List<String> keyList = new ArrayList<String>(map.keySet());
			List<Archiveable> valueList = new ArrayList<Archiveable>(keyList.size());
			
			// Iterate through each key, adding its value to the valueList
			for (String aKey : keyList) {
				Archiveable aValue = map.get(aKey);
				valueList.add(aValue);
			}
			
			// Save both lists separately
			this.putAttributeList(key + "KEY", keyList);
			this.putManyRelationship(key + "VALUE", valueList);
		}
	}
	
	public void putArchiveableToArchiveableMap(String key, Map<? extends Archiveable, ? extends Archiveable> map) {
		if (key != null && map != null) {
			// Get the keys and create an empty list for values
			List<Archiveable> keyList = new ArrayList<Archiveable>(map.keySet());
			List<Archiveable> valueList = new ArrayList<Archiveable>(keyList.size());
			
			// Iterate through each key, adding its value to the valueList
			for (Archiveable aKey : keyList) {
				Archiveable aValue = map.get(aKey);
				valueList.add(aValue);
			}
			
			// Save both lists separately
			this.putManyRelationship(key + "KEY", keyList);
			this.putManyRelationship(key + "VALUE", valueList);
		}
	}
	
	
	// Get methods
	public String getClassName(String key) {
		return this.attributes.get(key + "CLASSNAME");
	}
	
	public String getAttribute(String key) {
		return this.attributes.get(key);
	}
	
	public List<String> getAttributeList(String key) {
		return this.attributeLists.get(key);
	}
	
	public Archive getOneRelationship(String key) {
		
		return this.oneRelationships.get(key);
	}
	
	public List<Archive> getManyRelationship(String key) {
		return this.manyRelationships.get(key);
	}
	
	public Map<String, String> getPrimitiveToPrimitiveMap(String key) {
		List<String> keyList = this.getAttributeList(key + "KEY");
		List<String> valueList = this.getAttributeList(key + "VALUE");
		
		if (keyList != null && valueList != null && keyList.size() == valueList.size()) {
			Map<String, String> map = new HashMap<String, String>(keyList.size());
			for (int i = 0; i < keyList.size(); i++) {
				String aKey = keyList.get(i);
				String aValue = valueList.get(i);
				map.put(aKey, aValue);
			}
			
			return map;
		}
		return null;
	}
	
	public Map<String, Archive> getPrimitiveToArchiveableMap(String key) {
		List<String> keyList = this.getAttributeList(key + "KEY");
		List<Archive> valueList = this.getManyRelationship(key + "VALUE");
		
		if (keyList != null && valueList != null && keyList.size() == valueList.size()) {
			Map<String, Archive> map = new HashMap<String, Archive>(keyList.size());
			for (int i = 0; i < keyList.size(); i++) {
				String aKey = keyList.get(i);
				Archive aValue = valueList.get(i);
				map.put(aKey, aValue);
			}
			
			return map;
		}
		return null;
	}
	
	public Map<Archive, Archive> getArchiveableToArchiveableMap(String key) {
		List<Archive> keyList = this.getManyRelationship(key + "KEY");
		List<Archive> valueList = this.getManyRelationship(key + "VALUE");
		
		if (keyList != null && valueList != null && keyList.size() == valueList.size()) {
			Map<Archive, Archive> map = new HashMap<Archive, Archive>(keyList.size());
			for (int i = 0; i < keyList.size(); i++) {
				Archive aKey = keyList.get(i);
				Archive aValue = valueList.get(i);
				map.put(aKey, aValue);
			}
			
			return map;
		}
		return null;
	}
	
}
